<?php

namespace backend\models;


use common\rules\ParamsRule;
use yii\base\Model;
use Yii;
use yii\rbac\Permission;

/**
 * Class PermissionForm
 *
 * @property bool $isNew
 * @package backend\models
 */
class PermissionForm extends Model
{
    public $name;
    public $description;

    private $_oldParent;
    private $_parent;

    /**
     * @var Permission
     */
    private $_permission;

    /**
     * @param Permission $permission
     * @param array $config
     */
    public function __construct(Permission $permission = null, $config = [])
    {
        parent::__construct($config);
        if ($permission !== null) {
            $this->_permission = $permission;
            $this->name = $permission->name;
            $this->description = $permission->description;
            $this->_parent = $this->getParentByName($permission->name);
        }
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'description'], 'required'],
            ['name', 'match', 'pattern' => '/^[A-z0-9_\-\/\:\?&=]+$/'],
            ['name', 'nameUnique'],
        ];
    }

    /**
     * @param $name
     * @return null|Permission
     */
    public function getParentByName($name)
    {
        if ($pos = strrpos($name, '/')) {
            if ($permission = Yii::$app->getAuthManager()->getPermission(substr($name, 0, $pos))) {
                return $permission;
            }
        }

        return null;
    }

    /**
     * 检测名称是否唯一
     */
    public function nameUnique()
    {
        if ($this->getIsNew() || $this->_permission->name !== $this->name) {
            $role = Yii::$app->getAuthManager()->getPermission($this->name);
            if ($role) {
                $this->addError('name', '标识符已经被使用。');
            }
        }
    }

    /**
     * 是否是顶层app
     *
     * @return bool
     */
    public function isApp()
    {
        return !!preg_match('#^[A-z0-9\-_]+:$#', $this->name);
    }

    /**
     * 是否是路由权限
     *
     * @return bool
     */
    public function isRoutePermission()
    {
        return !!preg_match('#^[A-z0-9\-_]+:#', $this->name);
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'name' => '标识符',
            'description' => '描述',
        ];
    }

    /**
     * @return bool
     */
    public function getIsNew()
    {
        return !isset($this->_permission);
    }

    /**
     * @return bool|void
     */
    public function beforeValidate()
    {
        if (parent::beforeValidate()) {
            $this->name = trim($this->name, '/');

            if (!$this->isApp() && $this->isRoutePermission()) {
                if ($this->getIsNew()) {
                    $this->_parent = $this->getParentByName($this->name);
                } elseif ($this->_permission->name !== $this->name) {
                    $this->_oldParent = $this->_parent;
                    $this->_parent = $this->getParentByName($this->name);
                }

                if (!$this->_parent) {
                    $this->addError('name', '上级app或者模块不存在');
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    public function save()
    {
        if (!$this->validate()) {
            return false;
        }

        $query = parse_url($this->name, PHP_URL_QUERY);
        parse_str($query, $params);

        $authManager = Yii::$app->getAuthManager();
        if (!isset($this->_permission)) {
            $permission = $authManager->createPermission($this->name);
            $permission->description = $this->description;
            if ($params) {
                $rule = $this->getParamsRule();
                $permission->ruleName = $rule->name;
                $permission->data = $params;
            }
            $result = $authManager->add($permission);
            if ($result) {
                if ($this->_parent) {
                    $authManager->addChild($this->_parent, $permission);
                }
            }
            return $result;
        } else {
            if ($this->_oldParent) {
                $authManager->removeChild($this->_oldParent, $this->_permission);
            }
            $name = $this->_permission->name;
            $children = $authManager->getChildren($name);
            $this->_permission->name = $this->name;
            $this->_permission->description = $this->description;
            if ($params) {
                $rule = $this->getParamsRule();
                $this->_permission->ruleName = $rule->name;
                $this->_permission->data = $params;
            }
            $result = $authManager->update($name, $this->_permission);
            if ($result) {
                if ($this->_oldParent && $this->_parent) {
                    $authManager->addChild($this->_parent, $this->_permission);
                }
                $this->updateChildrenRecursive($children, $name, $this->name);
            }
            return $result;
        }
    }

    /**
     * 递归更新子节点
     *
     * @param $children
     * @param $oldName
     * @param $newName
     */
    protected function updateChildrenRecursive($children, $oldName, $newName)
    {
        $authManager = Yii::$app->getAuthManager();
        foreach ($children as $child) {
            $childOldName = $child->name;
            $children2 = $authManager->getChildren($childOldName);
            $child->name = str_replace($oldName, $newName, $childOldName);
            $authManager->update($childOldName , $child);
            $this->updateChildrenRecursive($children2 , $childOldName, $child->name);
        }
    }

    protected function getParamsRule()
    {
        $authManager = Yii::$app->getAuthManager();
        if (!$rule = $authManager->getRule('paramsRule')) {
            $rule = new ParamsRule([
                'name' => 'paramsRule'
            ]);
            $authManager->add($rule);
        }
        return $rule;
    }
}